iT邦幫忙

2025 iThome 鐵人賽

DAY 30
0
Mobile Development

Android 開發者養成計畫:從程式邏輯到作品集實戰系列 第 30

Day 30 App 的記憶力!資料庫與離線模式

  • 分享至 

  • xImage
  •  

今天的最終挑戰,是要為你的 App 加上一個「記憶力」。Room 資料庫,讓你的 App 即使在沒有網路的情況下,也能顯示資料,這會讓你的專案變得更完整、更專業。

比喻:

  • Retrofit (Day 25): 就像是你的「專業網路電話」,用來跟遠方的資料庫(伺服器)連線。
  • Room (Day 30): 就像是 App 內建的「個人圖書館」。當你用網路電話從遠方借了書(資料)之後,你可以把這些書存到自己的圖書館裡。這樣即使網路斷線,你還是能從自己的圖書館裡讀取資料。

步驟一:加入 Room 函式庫

要請「專業圖書館管理員」(Room)來幫忙,你需要在專案中簽約。
打開你的 build.gradle (Module: app) 檔案,在 dependencies 區塊中加入這些依賴。

`dependencies {
    // ... 其他依賴
    
    // Room Database 函式庫
    def room_version = "2.6.1"
    implementation "androidx.room:room-runtime:$room_version"
    annotationProcessor "androidx.room:room-compiler:$room_version"
    // For Kotlin: use kapt instead of annotationProcessor
    // kapt "androidx.room:room-compiler:$room_version"
}`

接著,點擊右上角的 "Sync Now",讓 Android Studio 下載並安裝這個函式庫。

步驟二:建立資料實體 (Entity)

這就像是為你的圖書館**「設計書架」**,告訴資料庫你要儲存的資料長什麼樣子。
建立一個新的 Java 類別,取名為 WeatherEntity

`import androidx.room.Entity;
import androidx.room.PrimaryKey;

@Entity(tableName = "weather_table")
public class WeatherEntity {

    @PrimaryKey(autoGenerate = true)
    private int id;
    
    private String cityName;
    private String description;
    private double temperature;
    private long lastUpdated; // 記錄資料更新時間

    // Constructor, getters and setters
    // 你可以讓 Android Studio 自動生成這些程式碼
}`
  • @Entity:這個註解告訴 Room,這個類別是資料庫裡的一張「表格」。
  • @PrimaryKey:告訴 Room,id 是這張表格的「主鍵」,每個資料都獨一無二。

步驟三:建立資料存取物件 (DAO)

這是你的**「圖書館借閱櫃檯」**,用來定義如何與資料庫互動。
建立一個新的 Java interface,取名為 WeatherDao

`import androidx.room.Dao;
import androidx.room.Insert;
import androidx.room.OnConflictStrategy;
import androidx.room.Query;

@Dao
public interface WeatherDao {

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    void insertWeather(WeatherEntity weather);

    @Query("SELECT * FROM weather_table WHERE cityName = :cityName")
    WeatherEntity getWeather(String cityName);
}`
  • @Dao:這個註解告訴 Room,這是一個資料存取介面。
  • @Insert:定義一個「插入」資料的方法。OnConflictStrategy.REPLACE 確保如果資料已存在,就直接覆蓋掉。
  • @Query:這是一個自訂查詢,用來從資料庫中「讀取」指定城市的資料。

步驟四:建立 Room 資料庫

現在,我們需要為你的 App 「建造這個圖書館」
建立一個新的 Java abstract class,取名為 AppDatabase,並繼承 RoomDatabase

`import androidx.room.Database;
import androidx.room.RoomDatabase;

@Database(entities = {WeatherEntity.class}, version = 1, exportSchema = false)
public abstract class AppDatabase extends RoomDatabase {
    public abstract WeatherDao weatherDao();
}`
  • @Database:告訴 Room,這是資料庫的配置。entities 指定要包含哪些表格,version 是資料庫的版本號。
  • abstract 方法:這個方法會回傳你的 WeatherDao 實例,讓你能夠存取資料庫。

步驟五:修改你的 ViewModel

這是最核心的部分,我們要讓你的 ViewModel 變得更聰明,能夠**「判斷」要從網路還是資料庫取得資料**。
在你的 WeatherViewModel 中,加入資料庫的相關邏輯。

// 在 WeatherViewModel.java 中...
private final WeatherDao weatherDao;
private final AppDatabase db;

public WeatherViewModel(Application application) {
    super(application);
    // 建立資料庫實例
    db = Room.databaseBuilder(
            application,
            AppDatabase.class, "weather-db"
    ).allowMainThreadQueries().build(); // 這裡為了方便示範,實際開發不建議在主執行緒查詢
    weatherDao = db.weatherDao();
}

public void fetchWeather(String cityName) {
    // 1. 先嘗試從資料庫讀取資料
    WeatherEntity cachedData = weatherDao.getWeather(cityName);
    if (cachedData != null && !isDataExpired(cachedData)) {
        // 如果資料存在且未過期,直接顯示
        _weatherData.setValue(cachedData.getDescription()); // 假設你只顯示描述
        return;
    }

    // 2. 如果資料不存在或已過期,才從網路抓取
    // ... Retrofit 網路請求的程式碼,這裡省略 ...
    
    call.enqueue(new Callback<WeatherResponse>() {
        @Override
        public void onResponse(...) {
            if (response.isSuccessful() && response.body() != null) {
                // 3. 網路請求成功,將新資料存入資料庫
                WeatherEntity newEntity = new WeatherEntity(...); // 建立新的資料物件
                weatherDao.insertWeather(newEntity);
                _weatherData.setValue(newEntity.getDescription());
            } else {
                // ... 錯誤處理 ...
            }
        }
        // ... onFailure() 錯誤處理 ...
    });
}

這個範例展示了「離線優先」的思維:先檢查 App 的「個人圖書館」,找不到或太舊了,才打「網路電話」出去詢問。

終於30天結束了,真的鬆了一大口氣,希望自己能更精進自己之後有機會能夠再次參加活動。


上一篇
Day 29- 打造 App 的質感!讓圖片載入又快又順
系列文
Android 開發者養成計畫:從程式邏輯到作品集實戰30
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言